use crate::object::{Boolean, ERROR_OBJ, Error, INTEGER_OBJ, Integer, Null, Object, RETURN_VALUE_OBJ, ReturnValue};
use crate::ast::{BlockStatement, BoolLiteral, ExpressionStatement, IfExpression, InfixExpression, IntegerLiteral, Node, PrefixExpression, Program, ReturnStatement, Statement};
use std::sync::Arc;

/**
 * 单例模式
 * 目的: 不用每次返回都创建一个新的Boolean对象
 */
pub const NULL:Null = Null;

pub const TRUE: Boolean = Boolean{
    value: true
};
pub const FALSE: Boolean = Boolean{
    value: false
};

macro_rules! new_error {
    ($format_str:expr, $($args:expr),*) => {
        Arc::new(Error {
            message: format!($format_str, $($args),*),
        })
    };
}

/**
 * 为了使测试用例通过，所要做的第一件事是在eval函数里扩展
 */
pub fn eval(node: &dyn Node) ->Arc<dyn Object>{
    if let Some(t) = node.as_any().downcast_ref::<Program>(){
        // return eval_statements(&t.statements);
        return eval_program(t);
    }else if let Some(t) = node.as_any().downcast_ref::<ExpressionStatement>(){
        return eval(&**t.expression.as_ref().unwrap());
    }else if let Some(t) = node.as_any().downcast_ref::<IntegerLiteral>(){
        return Arc::new(Integer{
            value: t.value
        });
    }else if let Some(t) = node.as_any().downcast_ref::<BoolLiteral>(){
        return Arc::new(native_bool_2_boolean_object(t.value));
    }else if let Some(t) = node.as_any().downcast_ref::<PrefixExpression>(){
        let right = eval(&**t.right.as_ref().unwrap());
        if is_error(right.as_ref()){
            return right;
        }
        return eval_prefix_expression(&t.operator, &*right);
    }else if let Some(t) = node.as_any().downcast_ref::<InfixExpression>(){
        let left = eval(&**t.left.as_ref().unwrap());
        if is_error(left.as_ref()){
            return left;
        }
        let right = eval(&**t.right.as_ref().unwrap());
        if is_error(right.as_ref()){
            return right;
        }
        return eval_infix_expression(&t.operator, &*left, &*right) ;
    }else if let Some(t) = node.as_any().downcast_ref::<BlockStatement>(){
        return eval_block_statement(&t);
        // return eval_statements(&t.statements);
    }else if let Some(t) = node.as_any().downcast_ref::<IfExpression>(){
        return eval_if_expression(&t);
    }else if let Some(t) = node.as_any().downcast_ref::<ReturnStatement>(){
        let val = eval(&**t.value.as_ref().unwrap());
        // 每当在Eval内部调用Eval时都需要检查错误消息，以免错误到处传递，导致在离发生错误很远的地方抛出错误：
        if is_error(val.as_ref()){
            return val;
        }
        return Arc::new(ReturnValue{value: val});
    }
    Arc::new(NULL)
}

fn eval_statements(stmts: &Vec<Arc<dyn Statement>>) -> Arc<dyn Object>{
    let mut result: Arc<dyn Object> = Arc::from(Null);
    for stmt in stmts{
        result = eval(&**stmt);
        // 在 evalProgramStatements 和 evalBlockStatements 中，会使用 evalStatements 对语句求值，其中会检查最后的求值结果是否是 object.ReturnValue。
        // 如果是，则停止求值并返回未封装的值。这一点很重要，这里不返回 object.ReturnValue，而是仅返回未封装的值，也就是用户期望返回的值。
        if let Some(t) = result.as_any().downcast_ref::<ReturnValue>(){
            return Arc::clone(&t.value);
        }
    }
    result
}



// 我相信你已经发现了当前实现的问题所在。以下解释会使这个问题更清楚：当遇到嵌套的块语句（这在 Monkey 程序中是完全有效的代码）时，我们无法在第一次遇到时就解包 object.ReturnValue 的值。这是因为这里需要进一步跟踪，以便停止最外面的块语句。
// 非嵌套的块语句可以在当前的实现中顺利运行。但是，要使嵌套的代码正常运行，首先要注意的是不能通过重用 evalStatements 函数对块语句求值。需要将其重命名为 evalProgram ，降低其通用性。
fn eval_program(program: &Program)->Arc<dyn Object>{
    let mut result = Arc::new(NULL) as Arc<dyn Object>;
    for stmt in program.statements.iter(){
        result = eval(&**stmt);
        if let Some(t) = result.as_any().downcast_ref::<ReturnValue>(){
            return Arc::clone(&t.value);
        }else if let Some(t) = result.as_any().downcast_ref::<Error>(){
            return Arc::from((*t).clone());
        }
    }
    result
}

// 这里明确了不解包返回值，只是检查每个求值结果的 Type() 。如果是 object.RETURN_VALUE_OBJ ，则只需返回 *object.ReturnValue ，无需解包其 Value 。这样如果有外部块语句，它就会停止执行，并冒泡至 evalProgram ，最后在这里解包。（之后在实现函数调用的求值时，会修改这里的最后一部分。）
fn eval_block_statement(block: &BlockStatement) -> Arc<dyn Object>{
    let mut result = Arc::new(NULL) as Arc<dyn Object>;
    for stmt in block.statements.iter(){
        result = eval(&**stmt);
        if result.inspect() != NULL.inspect(){
            if result.get_type() == RETURN_VALUE_OBJ || result.get_type() == ERROR_OBJ{
                return result;
            }
        } 
    }
    result
// unimplemented!()
}

/**
 * 将native bool转换为Boolean对象
 * 目的: 不用每次返回都创建一个新的Boolean对象
 */
fn native_bool_2_boolean_object(input: bool) -> Boolean{
    if input{
        TRUE
    }else{
        FALSE
    }
}

/**
 * 第一次调用eval后，right可能是Integer或者Boolean,也可能是Null。接着将这个right操作数传递给eval_prefix_expression，
 * 来查看这个函数能否处理其中的运算符：
 * 如果该函数不支持其中的运算符，则返回NULL。这不一定是最好的选择，但目前而言，这绝对是最简单的选择，目前还没有实现任何错误处理。
 * !的行为由eval_bang_operator_expression函数指定。
 */
fn eval_prefix_expression(operator: &str, right: &dyn Object) -> Arc<dyn Object>{
    if operator == "!"{
        return eval_bang_operator_expression(right);
    }else if operator == "-"{
        return eval_minus_operator_expression(right);
    }
    // Arc::from(NULL)
    new_error!("unknown operator: {}{}", operator, right.get_type())
}

fn eval_bang_operator_expression(right: &dyn Object)->Arc<dyn Object>{
    if let Some(o) = right.as_any().downcast_ref::<Boolean>(){
        if o.value == TRUE.value{
            return Arc::new( FALSE);
        }else{
            return Arc::new( TRUE);
        }
    }else if let Some(_) = right.as_any().downcast_ref::<Null>(){
        return Arc::new( TRUE);
    }
    Arc::new( FALSE)
}

fn eval_minus_operator_expression(right: &dyn Object)->Arc<dyn Object>{
    if right.get_type() != INTEGER_OBJ{
        // return Arc::new(NULL);
        return new_error!("unknown operator: -{}", right.get_type())
    }
    if let Some(r) = right.as_any().downcast_ref::<Integer>(){
        let value = r.value;
        return Arc::from(Integer{
            value: -value,
        });
    }
    // Arc::new(NULL)
    new_error!("unknown operator: -{}", right.get_type())
    // unimplemented!()
}

/**
 * 这里使用了指针比较来检查布尔值之间的相等性。这之所以可行，是因为程序中一直都在使用指向对象的指针，而布尔值只有 TRUE 和 FALSE 两个对象。因此，如果某项的值与 TRUE 的内存地址相同，那么它就是 true 。这也适用于 NULL 。
 * 但这种方法不适用于整数或其他稍后会添加的数据类型。对于 *object.Integer ，总是会有新分配的 object.Integer 实例，也就是使用新的指针。而整数不能通过比较不同的实例之间的指针来判断相等性，否则 5 == 5 将为 false 。这不是我们期望的行为。在这种情况下，要显式比较对象的值，而不是比较封装这些值的对象。
 * 这就是为什么要在 switch 语句中提前检查并匹配整数操作数，然后再匹配刚刚添加的 case 分支。只要先检查其他的操作数类型，然后再检查这些可以通过指针比较的操作数，代码就可以正常工作。
 * 对于智能指针，例如 Arc<T> 或 Rc<T> ，它们也实现了 PartialEq 。
 * - 当直接比较两个 Arc<T> （例如 arc1 == arc2 ）时，它们会比较智能指针内部的 值 。也就是说，如果它们指向的底层数据的值相等，那么智能指针本身也会被认为是相等的。
 * - 如果你想比较两个 Arc<T> 是否指向 同一个 内存分配（即它们是同一个 Arc 实例的克隆），你需要使用 Arc::ptr_eq() 或 Rc::ptr_eq() 方法。
 */
fn eval_infix_expression(operator: &str, left: &dyn Object, right: &dyn Object)->Arc<dyn Object>{
    // eprintln!("left.get_type()={}, right.get_type()={}", left.get_type(),right.get_type());
    if left.get_type() == INTEGER_OBJ && right.get_type() == INTEGER_OBJ{
        eval_integer_infix_expression(operator, left, right)
    }else if operator == "=="{
        // let a = left as *const dyn Object;
        // let b = right as *const dyn Object;
        // println!("left={}, right={}", left.inspect(), right.inspect());
        // println!("a={:?}, b={:?}", a, b);
        Arc::from(native_bool_2_boolean_object(left.inspect() == right.inspect()))
        // Arc::from(native_bool_2_boolean_object(ptr::eq(left as *const dyn Object, right as *const dyn Object)))
        // Arc::from(native_bool_2_boolean_object(Arc::ptr_eq(&Arc::new(left), &Arc::new(right))))
    }else if operator == "!="{
        // Arc::from(native_bool_2_boolean_object(!Arc::ptr_eq(&Arc::new(left), &Arc::new(right))))
        // Arc::from(native_bool_2_boolean_object(!ptr::eq(left as *const dyn Object, right as *const dyn Object)))
        Arc::from(native_bool_2_boolean_object(left.inspect() != right.inspect()))
    }else if left.get_type() != right.get_type(){
        new_error!("type mismatch: {} {} {}", left.get_type(), operator, right.get_type())
    }else {
        // Arc::new(NULL)
        new_error!("unknown operator: {} {} {}", left.get_type(), operator, right.get_type())
    }
// unimplemented!()
}

fn eval_integer_infix_expression(operator: &str, left: &dyn Object, right: &dyn Object)->Arc<dyn Object>{
    let mut left_val = 0;
    let mut right_val = 0;
    if let Some(_left) = left.as_any().downcast_ref::<Integer>(){
        left_val = _left.value;
    }
    if let Some(_right) = right.as_any().downcast_ref::<Integer>(){
        right_val = _right.value;
    }
    if operator == "+"{
        Arc::from(Integer{
            value: left_val + right_val
        })
    }else if operator == "-"{
        Arc::from(Integer{
            value: left_val - right_val
        })
    }else if operator == "*"{
        Arc::from(Integer{
            value: left_val * right_val
        })
    }else if operator == "/"{
        Arc::from(Integer{
            value: left_val / right_val
        })
    }else if operator == "<"{
        Arc::from(native_bool_2_boolean_object(left_val < right_val))
    }else if operator == ">"{
        Arc::from(native_bool_2_boolean_object(left_val > right_val))
    }else if operator == "=="{
        Arc::from(native_bool_2_boolean_object(left_val == right_val))
    }else if operator == "!="{
        Arc::from(native_bool_2_boolean_object(left_val != right_val))
    }else{
        // Arc::from(NULL)
        new_error!("unknown operator: {} {} {}", left.get_type(), operator, right.get_type())
    }
    // unimplemented!()

}

fn eval_if_expression(ie: &IfExpression) -> Arc<dyn Object>{
    let condition = eval(&**ie.condition.as_ref().unwrap());
    // eprintln!("inspect={}", (&*condition).inspect());
    // let alternative = ie.alternative;
    if is_error(condition.as_ref()){
        return condition;
    }
    if is_truthy(&*condition){
        eval(&*ie.consequence.as_ref().unwrap())
    }else if let Some(_) = ie.alternative{
        eval(&*ie.alternative.as_ref().unwrap())
    }else{
        Arc::from(NULL)
    }
    // unimplemented!()
} 

fn is_truthy(obj: &dyn Object)->bool{
    if obj.inspect() == NULL.inspect(){
        false
    }else if obj.inspect() == TRUE.inspect(){
        true
    }else if obj.inspect() == FALSE.inspect(){
        false
    }
    // if ptr::eq(obj as *const dyn Object, &NULL as *const dyn Object){
    //     false
    // }else if ptr::eq(obj as *const dyn Object, &TRUE as *const dyn Object){
    //     true
    // }else if ptr::eq(obj as *const dyn Object, &FALSE as *const dyn Object){
    //     false
    // }else{
    //     true
    // }
    // if Arc::ptr_eq(&Arc::new(obj), &Arc::new(&NULL)){
    //     false
    // }else if Arc::ptr_eq(&Arc::new(obj), &Arc::new(&TRUE)){
    //     true
    // }else if Arc::ptr_eq(&Arc::new(obj), &Arc::new(&FALSE)){
    //     false
    // }

    else{
        true
    }
// unimplemented!()
}


// 每当在Eval内部调用Eval时都需要检查错误消息，以免错误到处传递，导致在离发生错误很远的地方抛出错误：
fn is_error(obj: &dyn Object)->bool{
//     原因详解
// - 你在 src/object/mod.rs 里写了 impl PartialEq for dyn Object （以及 impl PartialEq<Null> for dyn Object ）。当没有显式写生命周期时， dyn Object 在 impl 头部默认是 dyn Object + 'static 。
// - 当在函数 fn is_error(obj: &dyn Object) -> bool 里使用 == 或 != 时， obj 的类型是 &'a dyn Object （某个非 'static 的生命周期 'a ），编译器会去匹配你为 dyn Object + 'static 提供的 PartialEq 实现。
// - 由于该实现只对 'static 的 trait object 生效，方法解析会试图强制 'a: 'static ，从而触发 “lifetime may not live long enough / requires that '1 must outlive 'static” 的报错。
// - 即使比较的是 obj == obj ，只要运算符解析要用到你为 dyn Object 提供的 PartialEq 实现（默认 'static ），就会出现上述生命周期不满足的问题。这与比较的逻辑是否成立无关，纯粹是 impl 选择时引入了 'static 约束。
// 可选修复方案
// - 为 dyn Object 的 PartialEq 实现显式添加生命周期参数，使其对任意生命周期的 trait object 都适用。
// - 或者避免 PartialEq ，用类型断言判错（ as_any().downcast_ref::<Error>().is_some() ），这不涉及 'static ，更稳妥。
// 建议修改
// 把 src/object/mod.rs 里的 PartialEq 实现改为带生命周期的版本：
    // if *obj == *obj{
    //     return obj.get_type() == ERROR_OBJ;
    // }
    if !is_null(obj){
        return obj.get_type() == NULL.get_type();
    }
    // obj.as_any().downcast_ref::<Error>().is_some()
    false
}

fn is_null(obj: &dyn Object) -> bool{
    obj.as_any().downcast_ref::<Null>().is_some()
}

#[cfg(test)]
mod tests;